/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "icache.h"
#include "spi.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "cJSON.h"
#include "fml_debug.h"
//#include "fml_key.h"
#include "fml_ota.h"
#include "fml_config.h"
//#include "hal_pwm_gpio.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */


/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern int CJSON_CDECL cJSON_main(void);

typedef  void (*pFunction)(void);

pFunction Jump_To_Application;
uint32_t JumpAddress;

static void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

uint8_t upgrd_buf[FLASH_PAGE_SIZE] = {0};
uint8_t check_buf[FLASH_PAGE_SIZE] = {0};

bool upgrade_system(uint32_t app_size)
{
#if 1  
    uint32_t cnt = 0;
    uint32_t i = 0, j = 0, z = 0;

    //UPGRADE_INFO *info = &s_upgrade_info;
    //uint32_t app_addr = 0;
    //uint32_t app_size = 0;
    uint32_t page_num = 0;

  
    //if (0 == strcmp(info->cur_version, info->old_version.version))
    //{
        //app_addr = info->old_version.ver_addr;
        //app_size = info->old_version.ver_size;
    //}
    //else if (0 == strcmp(info->cur_version, info->new_version.version))
    //{
        //app_addr = info->new_version.ver_addr;
        //app_size = info->new_version.ver_size;
    //}
    //else
    //{
    //    return -1;
    //}
    printf("Upgrade App Size: %d\r\n", app_size);
    
    if (0 == hal_flash_erase(APP_START_ADDR, app_size))
    {
        printf("Erase Flash 0x%08x size %d\n", APP_START_ADDR, app_size);
    }
    
    page_num = (app_size / FLASH_PAGE_SIZE) + ((app_size % FLASH_PAGE_SIZE) ? 1 : 0);
    printf("total:%d page", page_num);
    printf("start upgrd system, wait complete...\r\n");
    for (i = 0; i < page_num; i++)
    {
        hal_flash_read(upgrd_buf, APP_BAK_START_ADDR + i * FLASH_PAGE_SIZE, sizeof(upgrd_buf));
        hal_flash_write(upgrd_buf, APP_START_ADDR + i * FLASH_PAGE_SIZE, sizeof(upgrd_buf));
        hal_flash_read(check_buf, APP_START_ADDR + i * FLASH_PAGE_SIZE, sizeof(check_buf));
        
        for (j = 0; j < FLASH_PAGE_SIZE; j++)
        {
            if (check_buf[j] != upgrd_buf[j])
            {
                printf("upgrd page: %d error [%d]:[%d].\r\n", i, j, check_buf[j], upgrd_buf[j]);
                goto err_end;
            }
        }
        
        memset(upgrd_buf, 0, sizeof(upgrd_buf));
        memset(check_buf, 0, sizeof(check_buf));

        printf("%.2f%%.\r\n", ((100.00 / page_num) * (++cnt)));
    }
    printf("Upgrade SUC, Congratulations.\r\n");
    hal_flash_erase(CONFIG_START_ADDR, CONFIG_SIZE);
    return true;

err_end:
    printf("Upgrade fail.\r\n");
    return false;
#endif
}



/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    cJSON *ota_info = NULL;
    uint8_t buff[8] = {0};
    
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    //MX_GPIO_Init();
    //MX_SPI1_Init();
    //MX_SPI2_Init();
    //MX_ICACHE_Init();
    fml_debug_init();
    
    //fml_key_init();

    //if(DEV_Module_Init()!=0)
    //    return -1;
    
    printf("BOOTLOADER is running\r\n");
    
    fml_config_init();
    
    if (g_ota_info.app_update_flag)
    {
        if (upgrade_system(g_ota_info.app_size))
        {
            fml_ota_set_ota_info(0, g_ota_info.app_md5, g_ota_info.app_size);
        }
    }
#if 0
    memset(buff, 0, sizeof(buff));
    fml_ota_flash_read(buff, CONFIG_START_ADDR, sizeof(buff));
 
    if (*(uint32_t *)buff == 0xAA5555AA)
    {
        upgrade_system(*(uint32_t *)(buff + 4));
    }
#endif
    
    printf("Ready to Jump App 0x%08x\n", APP_START_ADDR);
    
    //HAL_DeInit();
    //__HAL_RCC_SYSCFG_CLK_DISABLE();
    //__disable_irq();
    
    HAL_Delay(1000);
    
    if (((*(__IO uint32_t*)APP_START_ADDR) & 0x2FFE0000 ) == 0x20000000)
    { 
        /* Jump to user application */
        JumpAddress = *(__IO uint32_t*)(APP_START_ADDR + 4);
        Jump_To_Application = (pFunction)JumpAddress;
        /* Initialize user application's Stack Pointer */
        __set_MSP(*(__IO uint32_t*)APP_START_ADDR);
        Jump_To_Application();
    }
    
    printf("Jump App Failed\n");
    
    while (1);
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE0) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 55;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */


#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
